{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TVM 节点反射"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`tvm/include/tvm/node/reflection.h` 是 TVM（Tensor Virtual Machine）库中的一个头文件，用于实现 TVM 中的反射机制。名为 `Reflector` 的类，它是整个反射机制的核心。`Reflector` 类的主要作用是通过序列化和反序列化操作，将计算图中的各种节点、参数和数据结构进行转换，以便在不同的硬件平台上进行部署。\n",
    "\n",
    "`Reflector` 类中的方法包括：\n",
    "\n",
    "1. `Reflector::Init()`：初始化 `Reflector` 对象。在构造函数中调用此方法。\n",
    "2. `Reflector::Run()`：执行反射操作。首先对计算图进行序列化，然后根据目标平台对序列化后的数据进行反序列化，最后执行反序列化后的计算图。\n",
    "3. `Reflector::Export()`：导出指定节点的信息。将指定节点的信息导出到一个字符串中。\n",
    "4. `Reflector::Import()`：导入指定节点的信息。从一个字符串中读取节点信息，并将其反序列化为一个 `ReflectorNode` 对象。\n",
    "5. `Reflector::GetAttrs()`：获取指定节点的属性列表。返回一个包含属性名称和值的映射（`std::unordered_map<string, AttrValue>`）。\n",
    "6. `Reflector::SetAttrs()`：设置指定节点的属性列表。使用给定的属性值更新节点的属性。\n",
    "7. `Reflector::ResetGraph()`：重置计算图。清除所有节点、参数和数据结构。\n",
    "8. `Reflector::LoadGraph()`：加载计算图。从磁盘或其他存储介质中读取计算图的数据结构，并反序列化为 `ReflectorNode` 对象。\n",
    "9. `Reflector::FindNode()`：查找指定名称的节点。返回一个指向具有指定名称的节点的指针。\n",
    "10. `Reflector::FindOutput(const std::string& name)`：查找具有指定名称的输出节点。返回一个指向具有指定名称的输出节点的指针。\n",
    "11. `Reflector::FindInput(const std::string& name)`：查找具有指定名称的输入节点。返回一个指向具有指定名称的输入节点的指针。\n",
    "12. `Reflector::FindNextNode(const ReflectorNode* node)`：查找给定节点的下一个节点。返回一个指向下一个节点的指针，如果没有找到，则返回 `nullptr`。\n",
    "13. `Reflector::FindAllNodes(const std::function<bool(const ReflectorNode*)>& filter)`：查找满足给定过滤条件的所有节点。返回一个包含满足条件的节点指针的列表。\n",
    "14. `Reflector::FindSubgraph(const std::vector<const ReflectorNode*>& nodes)`：查找给定节点集合所在的子图。返回一个表示子图的对象，该对象包含了子图中的所有节点和连接关系。\n",
    "15. `Reflector::DumpGraph()`：将计算图以文本形式输出到标准输出（或指定的文件）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `NodeGetAttr`、`NodeListAttrNames` 和 `MakeNode`\n",
    "\n",
    "1. `NodeGetAttr` 函数用于获取对象的属性值。它接受两个参数：`args` 和 `ret`。`args` 是包含输入参数的数组，`ret` 是指向返回值的指针。首先，代码检查 `args[0]` 的类型码是否为 `kTVMObjectHandle`，然后将 `args[0]` 的值转换为 `Object*` 类型。接下来，它调用 `ReflectionVTable::Global()->GetAttr` 函数来获取对象的属性值，并将结果存储在 `ret` 指向的位置。\n",
    "\n",
    "2. `NodeListAttrNames` 函数用于列出对象的所有属性名称。它也接受两个参数：`args` 和 `ret`。`args` 是包含输入参数的数组，`ret` 是指向返回值的指针。首先，代码检查 `args[0]` 的类型码是否为 `kTVMObjectHandle`，然后将 `args[0]` 的值转换为 `Object*` 类型。接下来，它调用 `ReflectionVTable::Global()->ListAttrNames` 函数来获取对象的属性名称列表，并将其存储在新的 `std::vector<std::string>` 对象中。最后，它创建包装器函数，该函数接受整数参数 `i`，并根据 `i` 的值返回相应的属性名称或属性名称列表的大小。\n",
    "\n",
    "3. `MakeNode` 函数用于创建新的对象。它接受 `const TVMArgs&` 类型的参数 `args` 和指向返回值的指针 `rv`。首先，代码从 `args` 中提取对象的类型键（`type_key`），并创建新的 `TVMArgs` 对象 `kwargs`，其中包含剩余的参数。然后，它调用 `ReflectionVTable::Global()->CreateObject` 函数来创建新的对象，并将结果存储在 `rv` 指向的位置。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查看对应的 Python 接口示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tvm\n",
    "\n",
    "# MakeNode -> tvm.ir.make_node\n",
    "x = tvm.ir.make_node(\"IntImm\", dtype=\"int32\", value=10, span=None)\n",
    "assert isinstance(x, tvm.tir.IntImm)\n",
    "assert x.value == 10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其余两个类被打包到 `Object`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;31mSignature:\u001b[0m \u001b[0mtvm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mruntime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mObject\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__getattr__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mDocstring:\u001b[0m <no docstring>\n",
      "\u001b[0;31mSource:\u001b[0m   \n",
      "    \u001b[0;32mdef\u001b[0m \u001b[0m__getattr__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;31m# specially check handle since\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;31m# this is required for PackedFunc calls\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;32mif\u001b[0m \u001b[0mname\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"handle\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m            \u001b[0;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"handle is not set\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m            \u001b[0;32mreturn\u001b[0m \u001b[0m_ffi_node_api\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNodeGetAttr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;32mexcept\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m            \u001b[0;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"{type(self)} has no attribute {name}\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFile:\u001b[0m      /media/pc/data/lxw/ai/tvm/xinetzone/__pypackages__/3.10/lib/tvm/runtime/object.py\n",
      "\u001b[0;31mType:\u001b[0m      function"
     ]
    }
   ],
   "source": [
    "tvm.runtime.Object.__getattr__??"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;31mSignature:\u001b[0m \u001b[0mtvm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mruntime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mObject\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__dir__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mDocstring:\u001b[0m Default dir() implementation.\n",
      "\u001b[0;31mSource:\u001b[0m   \n",
      "    \u001b[0;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0mclass_names\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdir\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0mfnames\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_ffi_node_api\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNodeListAttrNames\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0msize\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfnames\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
      "\u001b[0;34m\u001b[0m        \u001b[0;32mreturn\u001b[0m \u001b[0msorted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfnames\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mclass_names\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFile:\u001b[0m      /media/pc/data/lxw/ai/tvm/xinetzone/__pypackages__/3.10/lib/tvm/runtime/object.py\n",
      "\u001b[0;31mType:\u001b[0m      function"
     ]
    }
   ],
   "source": [
    "tvm.runtime.Object.__dir__??"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tvmz",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
